home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / printing / bjf-1.000 / bjf-1 / bjf / bjf.c < prev    next >
C/C++ Source or Header  |  1994-03-27  |  25KB  |  957 lines

  1. /* 
  2.  * Copyright 1994 Chris Smith
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and its
  5.  * documentation for any purpose and without fee is hereby granted,
  6.  * provided that the above copyright notice appears in all copies and that
  7.  * both that copyright notice and this permission notice appears in
  8.  * supporting documentation.  I make no representations about the
  9.  * suitability of this software for any purpose.  It is provided "as is"
  10.  * without express or implied warranty.
  11.  */
  12.  
  13. /* Canon BJ filter.
  14.    Implement overstriking with underline and boldface.
  15.    Quote control characters other than \t \n \r \b \f.
  16.    Truncate long lines. */
  17.  
  18. #include "bj.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <stdarg.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <getopt.h>
  25. #include <signal.h>
  26.  
  27. /* Command options 
  28.  
  29.    -width N positions the printout to center a line of length N chars.
  30.      For proportional fonts, N is taken in 12 cpi units.  Long lines are
  31.      truncated at the right edge of the print area, which may be more
  32.      than N chars.
  33.  
  34.    -height N prints N lines per page, positioned to vertically center
  35.      a full page of N lines.  -height 66 specifies the whole sheet, and
  36.      the printout is positioned accordingly, but lines 1,65,66 are not
  37.      printable and are not sent.  This is what is needed for pr and
  38.      nroff output using 66 lines/page instead of formfeeds.
  39.  
  40.    -cpi N, N in { 10 12 17 PS }, chooses a font of that pitch in chars/in.
  41.  
  42.    -lpi N.N sets the interline spacing to N.N lines/in.  Default 6.
  43.  
  44.    -font X, X in { courier, gothic, prestige }, uses that resident font.
  45.      courier is the default, and best.  Can't be used with -draft
  46.      or -landscape.
  47.  
  48.    -code-page N, N in { 437, 850 }, uses that code page.  Default 437.
  49.      Conflicts with -landscape, -two-up, -four-up.
  50.  
  51.    -paper-length N.N gives the height of the physical paper in inches.
  52.  
  53.    -draft uses draft mode (light ink, high speed) output.
  54.      There's only one draft font, so -draft and -font conflict.
  55.  
  56.    -landscape downloads a sideways font and rotates the page.  
  57.      Size is typically 132x60.  Conflicts with -font but not -draft.
  58.  
  59.    -two-up prints two pages side by side.  Implies -landscape.
  60.      Size is typically 80x60.  (WIDTH is the width of one of the two pages.)
  61.  
  62.    -four-up prints four pages per sheet with a tiny downloaded font.  
  63.      Conflicts with -font and -landscape.
  64.  
  65.    -odd prints every other sheet starting at the first.
  66.  
  67.    -even prints every other sheet starting at the second, followed by
  68.      a blank page if the last sheet was not even.  */
  69.  
  70. const struct option long_options[] =
  71. {
  72.   { "width",        required_argument, 0, 'w' },
  73.   { "height",        required_argument, 0, 'h' },
  74.   { "cpi",        required_argument, 0, 'c' },
  75.   { "lpi",        required_argument, 0, 'v' },
  76.   { "font",        required_argument, 0, 'f' },
  77.   { "code-page",    required_argument, 0, 'C' },
  78.   { "paper-length",    required_argument, 0, 'V' },
  79.   { "draft",        no_argument,      0, 'd' },
  80.   { "landscape",    no_argument,     0, 'l' },
  81.   { "two-up",        no_argument,     0, '2' },
  82.   { "four-up",        no_argument,     0, '4' },
  83.   { "odd",        no_argument,     0, 'o' },
  84.   { "even",        no_argument,     0, 'e' },
  85.   { "l",        no_argument,     0, 'l' },
  86.   { "c",        required_argument, 0, 'c' },
  87.   { "f",        required_argument, 0, 'f' },
  88.   { 0 },
  89. };
  90.  
  91. const char short_options[] = "w:h:c:v:f:dl24eo";
  92.  
  93. /* Command flags */
  94.  
  95. static const char *fflag;
  96. static int wflag, hflag, cflag, dflag, lflag;
  97. static int x2flag, x4flag, eflag, oflag, Cflag;
  98. static float vflag, Vflag;
  99.  
  100. /* Page buffer size. */
  101. #define MAXCOL 179
  102. #define MAXLINE 160
  103.  
  104. /* Page buffer and corresponding attributes. */
  105. static uchar buf[MAXLINE][MAXCOL];
  106. static uchar attr[MAXLINE][MAXCOL];
  107.  
  108. /* attribute bits */
  109. #define BOLD 1
  110. #define UNDERLINE 2
  111. #define OVERSTRIKE 4
  112.  
  113. /* page bounds: page image is at buf[0..maxcol-1][0..maxline-1] */
  114. int maxcol, maxline;
  115.  
  116. /* internal margins for 2-up and 4-up, col # and line # of subpage images. */
  117. int centercol, centerline;
  118.  
  119. /* first and last lines of buf[] to actually print, for clipping -h66 */
  120. int topline, botline;
  121.  
  122. /* distance of first char from left end of 8" print width, in 1/120" */
  123. int left_margin;
  124.  
  125. /* distance of first line from first printable line, in baselineskips */
  126. int top_margin;
  127.  
  128. /* true if 1-sided, reverse the page order.
  129.    If reverse is true, npages is # of pages in file. */
  130. int reverse;
  131. int npages;
  132.  
  133. /* overstrike list */
  134. struct overstrike {
  135.   struct overstrike *next;
  136.   uchar *charloc;
  137.   uchar c;
  138. };
  139. struct overstrike *overstrikes;
  140.  
  141. /* file positions of page starts, for reversing the pages */
  142. struct page_list
  143. {
  144.   unsigned pos;
  145.   struct page_list *next;
  146. };
  147. struct page_list *page_list;
  148.  
  149. /* flag for ^C handler, whether to produce trailing \f if we are aborted */
  150. static volatile sig_atomic_t in_page;
  151.  
  152. /* forwards */
  153. static void usage (void);
  154. static void fatal (char *fmt, ...);
  155. static void check_options (void);
  156. static void do_layout (void);
  157. static void send_init (void);
  158. static void send_file (void);
  159. static void send_fin (void);
  160. static void init_reverse (void);
  161. static int seek_prev_page (void);
  162. static void init_page (void);
  163. static int read_page (int bottom_half_flag, int right_half_flag);
  164. static void write_page (int vt_flag);
  165. static void write_line (uchar *charp, uchar *attrp, int stride, int len);
  166. static void write_two_lines (uchar *c1, uchar *c2, int stride, int len);
  167. static int setattr (int lpa, int a);
  168. static void do_overstrikes (uchar *charloc);
  169. static void sigint (int signo);
  170.  
  171. int main (int argc, char *argv[])
  172. {
  173.   int t;
  174.   char *tail;
  175.  
  176.   /* Parse options */
  177.  
  178.   for (;;)
  179.     switch (getopt_long_only (argc, argv, short_options, long_options, &t)) {
  180.     case -1:
  181.       goto done;
  182.  
  183.     when 'w':
  184.       wflag = strtol (optarg, &tail, 10);
  185.       if (*tail) usage ();
  186.  
  187.     when 'h':
  188.       hflag = strtol (optarg, &tail, 10);
  189.       if (*tail) usage ();
  190.  
  191.     when 'c':
  192.       if (! strcasecmp (optarg, "PS"))
  193.     cflag = -1;
  194.       else {
  195.     cflag = strtol (optarg, &tail, 10);
  196.     if (*tail) usage (); }
  197.  
  198.     when 'v':
  199.       vflag = strtod (optarg, &tail);
  200.       if (*tail) usage ();
  201.  
  202.     when 'f':
  203.       fflag = optarg;
  204.  
  205.     when 'd':
  206.       dflag = 1;
  207.  
  208.     when 'l':
  209.       lflag = 1;
  210.  
  211.     when '2':
  212.       x2flag = 1;
  213.  
  214.     when '4':
  215.       x4flag = 1;
  216.  
  217.     when 'o':
  218.       oflag = 1;
  219.  
  220.     when 'e':
  221.       eflag = 1;
  222.  
  223.     when 'C':
  224.       Cflag = strtol (optarg, &tail, 10);
  225.       if (*tail) usage ();
  226.  
  227.     when 'V':
  228.       Vflag = strtod (optarg, &tail);
  229.       if (*tail) usage ();
  230.  
  231.     when '?':
  232.       usage ();
  233.  
  234.     otherwise:
  235.       abort ();
  236.     }
  237.  
  238.  done:
  239.   if (optind != argc)
  240.     fatal ("bjf is a filter and reads from stdin; use 'bjf <file' not "
  241.        "'bjf file'");
  242.  
  243.   /* set up */
  244.  
  245.   check_options ();
  246.   do_layout ();
  247.   if (reverse)
  248.     init_reverse ();
  249.  
  250.   signal (SIGINT, sigint);
  251.  
  252.   /* print */
  253.  
  254.   send_init ();
  255.   send_file ();
  256.   send_fin ();
  257.  
  258.   return 0;
  259. }
  260.  
  261. /* Give help */
  262.  
  263. static void usage ()
  264. {
  265.   fatal ("Usage: bjf [-wheo24dcvf] <in >out\n\
  266. Flags (with default values)\n\
  267.     -width 80    center a line of N chars\n\
  268.     -height 60    vertically center N lines per page\n\
  269.     -even    even pages only\n\
  270.     -odd    odd pages only\n\
  271.     -two-up    two pages side by side, landscape\n\
  272.     -four-up    four pages per side, really tiny\n\
  273.     -landscape    one-up landscape\n\
  274.     -draft    draft mode, use less ink\n\
  275.     -cpi 10    font pitch (chars per inch), 10 12 17 or PS (proportional)\n\
  276.     -lpi 6.0    line spacing (lines per inch)\n\
  277.     -font courier       use resident font Courier, Prestige, or Gothic\n\
  278.     -paper-length 11.0  length of paper in the printer (inches)\n\
  279.     -code-page 437      use resident font code page 437 or 850");
  280. }
  281.  
  282. /* Die */
  283.  
  284. static void fatal (char *fmt, ...)
  285. {
  286.   va_list ap;
  287.   va_start (ap, fmt);
  288.   vfprintf (stderr, fmt, ap);
  289.   fprintf (stderr, "\n");
  290.   va_end (ap);
  291.   exit (1);
  292. }
  293.  
  294. /* Validity checks */
  295.  
  296. static void check_options ()
  297. {
  298.   /* default missing options */
  299.  
  300.   if (wflag == 0) wflag = 80;        /* -width */
  301.   if (hflag == 0) hflag = 60;        /* -height */
  302.   if (vflag == 0) vflag = 6;        /* -lpi */
  303.   if (cflag == 0) cflag = 10;        /* -cpi */
  304.   if (Vflag == 0) Vflag = 11.0;        /* -paper-length */
  305.  
  306.   /* reverse the pages if not 2-sided */
  307.   if (! (eflag || oflag))
  308.     reverse = 1;
  309.  
  310.   /* -cpi */
  311.   if (cflag != 10 && cflag != 12 && cflag != 17 && cflag != -1)
  312.     fatal ("-cpi must be 10, 12, 17, or PS");
  313.  
  314.   /* -width -height */
  315.   if (wflag <= 0 || hflag <= 0)
  316.     fatal ("no negative numbers please");
  317.  
  318.   /* -lpi */
  319.   if (vflag < 360.0 / 255 || vflag > 360)
  320.     fatal ("-lpi must be less absurd");
  321.   vflag = ((int) (0.5 + vflag * 360.0)) / 360.0;
  322.  
  323.   /* -paper-length */
  324.   if (Vflag < 1 || Vflag > 17)
  325.     fatal ("-paper-length must be in 1..17");
  326.   Vflag = ((int) (0.5 + Vflag * 360.0)) / 360.0;
  327.  
  328.   /* -font */
  329.   if (! check_font_name (fflag))
  330.     fatal ("-font must be COURIER, PRESTIGE, or GOTHIC");
  331.  
  332.   /* conflicting flags */
  333.   if (x2flag + x4flag + lflag + (!! fflag | !! Cflag) > 1)
  334.     fatal ("only one of -landscape -two-up -four-up -font -code-page please");
  335.   if (fflag && dflag)
  336.     fatal ("-font and -draft can't be used together");
  337.   if (eflag && oflag)
  338.     fatal ("only one of -even or -odd please");
  339.   if ((x2flag | x4flag | lflag) & (cflag != 10 || vflag != 6))
  340.     fatal ("can't use -cpi or -lpi with downloaded font");
  341.   if (cflag == -1 && dflag)
  342.     fatal ("can't use -draft -cpi PS, the printer won't do it");
  343. }
  344.  
  345. /* Set globals to position output on page */
  346.  
  347. static void do_layout ()
  348. {
  349.   int maxwidth, maxheight;
  350.   int pxlh, pxlw;
  351.   int nclip;
  352.  
  353.   /* select download font, if any */
  354.   init_font (lflag, x2flag, x4flag);
  355.  
  356.   if (x2flag) {
  357.     /* two-up landscape layout with downloaded 22x37 font */
  358.  
  359.     pxlh = myfont[0];
  360.     pxlw = myfont[1];
  361.     
  362.     /* paper height is 11 in, less 1/4 inch at top, bottom and center. */
  363.  
  364.     maxwidth = 0.5 * (Vflag - 0.75) * 360. / pxlw;
  365.     if (wflag > maxwidth)
  366.       fatal ("-width too large, max with -two-up is %d", maxwidth);
  367.       
  368.     top_margin = (maxwidth - wflag) / 3;
  369.     maxcol = maxwidth - top_margin;
  370.     top_margin += (int) (0.25 * 360 / pxlw);
  371.  
  372.     /* printable width is 8 in; choose left margin to center the page */
  373.  
  374.     maxheight = 8 * 360 / pxlh;
  375.     if (hflag > maxheight)
  376.       fatal ("-height too large, max with -two-up is %d", maxheight);
  377.  
  378.     left_margin = 0.5 + (8 * 120 - hflag * pxlh / 3.0) / 2.0;
  379.     topline = 0;
  380.     botline = maxline = hflag; }
  381.  
  382.   else if (lflag) {
  383.     /* one-up landscape layout with downloaded 24x42 font */
  384.  
  385.     pxlh = myfont[0];
  386.     pxlw = myfont[1];
  387.     
  388.     /* paper height is 11 in, less 1/4 inch at top and bottom */
  389.  
  390.     maxwidth = (Vflag - 0.5) * 360. / pxlw;
  391.     if (wflag > maxwidth)
  392.       fatal ("-width too large, max with -landscape is %d", maxwidth);
  393.       
  394.     top_margin = (maxwidth - wflag) / 2;
  395.     maxcol = maxwidth - top_margin;
  396.     top_margin += (int) (0.25 * 360 / pxlw);
  397.  
  398.     /* printable width is 8 in; choose left margin to center the page */
  399.  
  400.     maxheight = 8 * 360 / pxlh;
  401.     if (hflag > maxheight)
  402.       fatal ("-height too large, max with -landscape is %d", maxheight);
  403.  
  404.     left_margin = 0.5 + (8 * 120 - hflag * pxlh / 3.0) / 2.0;
  405.     topline = 0;
  406.     botline = maxline = hflag; }
  407.  
  408.   else if (x4flag) {
  409.     /* four-up portrait layout with downloaded 17x24 font */
  410.  
  411.     pxlw = myfont[0];
  412.     pxlh = myfont[1];
  413.     
  414.     /* printable width is 8 in minus min 1/4 inch center margin */
  415.  
  416.     maxwidth = 0.5 * (8 - 0.25) * 360 / pxlw;
  417.     if (wflag > maxwidth)
  418.       fatal ("-width too large, max with -four-up is %d", maxwidth);
  419.       
  420.     left_margin = 0.5 + ((8 - 0.25) * 120 - 2 * wflag * pxlw / 3.0) / 3.0;
  421.     centercol = wflag + (left_margin * 3 + 0.25 * 360) / pxlw;
  422.     maxcol = wflag + left_margin * 3 / pxlw;
  423.  
  424.     /* paper height is 11 in, less 1/4 inch at top, bottom and center. */
  425.  
  426.     maxheight = 0.5 * (Vflag - 0.75) * 360 / pxlh;
  427.     if (hflag > maxheight)
  428.       fatal ("-height too large, max with -four-up is %d", maxheight);
  429.  
  430.     top_margin = (maxheight - hflag) / 3;
  431.     top_margin += (int) (0.25 * 360 / pxlh);
  432.     topline = 0;
  433.     maxline = hflag;
  434.     centerline = top_margin + hflag;
  435.     botline = centerline + hflag; }
  436.  
  437.   else {
  438.     /* portrait-mode layout with resident fonts */
  439.  
  440.     /* printable width is 8 in; choose left margin to center the line */
  441.  
  442.     pxlw = 360 / (cflag != -1 ? cflag : 12);
  443.     maxwidth = 8 * 360 / pxlw;
  444.     if (wflag > maxwidth)
  445.       fatal ("-width too large, max at %d cpi is %d", cflag, maxwidth);
  446.     
  447.     left_margin = 0.5 + (8 * 120 - wflag * pxlw / 3.0) / 2.0;
  448.     if (cflag == -1)
  449.       maxcol = MAXCOL;
  450.     else
  451.       maxcol = wflag + left_margin * 3 / pxlw;
  452.  
  453.     /* usable height is 11 in, we will clip top and bottom if necessary
  454.        to provide the needed top and bottom margin */
  455.  
  456.     maxheight = (int) (Vflag * vflag);
  457.     if (hflag > maxheight)
  458.       fatal ("-height too large, max at %g lpi is %d", vflag, maxheight);
  459.  
  460.     if (hflag > MAXLINE)
  461.       fatal ("-height too large, rebuild bjf to exceed %d", MAXLINE);
  462.  
  463.     top_margin = (maxheight - hflag) / 2;
  464.     maxline = hflag;
  465.  
  466.     /* actual vertical print area is not 11 in; the printer requires
  467.        roughly quarter-inch margins at top and bottom.  If the requested
  468.        page format is higher than that, actually send only enough lines
  469.        to fill 10.5 inches; the printer will put the first one on the
  470.        top printable line, and the bottom one will fit, and the truncated
  471.        page image will be vertically centered.  Clip the same number of
  472.        lines from top and bottom, or if odd, clip the extra one from the 
  473.        bottom. */
  474.     nclip = maxline - (int) ((Vflag - 0.5) * vflag);
  475.     if (nclip > 0) {
  476.       topline = nclip / 2;
  477.       botline = maxline - (nclip - topline); }
  478.     else
  479.       topline = 0, botline = maxline;
  480.   }
  481. }
  482.  
  483. /* Send init string to printer */
  484.  
  485. static void send_init ()
  486. {
  487.   do_init (fflag, cflag, Cflag, dflag, vflag, Vflag);
  488. }
  489.  
  490. /* Send reset string to printer */
  491.  
  492. static void send_fin ()
  493. {
  494.   do_fin ();
  495. }
  496.  
  497. /* Read file, send all (1-sided) or every other (2-sided) page to printer */
  498.  
  499. static void send_file ()
  500. {
  501.   unsigned pageno, select_zeros, select_ones;
  502.   unsigned select_right_half, select_top_half;
  503.   unsigned select_bottom_half;
  504.  
  505.   /* PAGENO counts from 0, so -odd should produce pagenos 0, 2, ...
  506.      -two-up sends each page to the printer as it is done, and write_page
  507.          writes half a sheet each time.
  508.      -two-up -odd sends 0, 1, 4, 5, 8, 9, ...
  509.      -four-up builds a complete quad page image then sends it.
  510.          writing happens at pagenos 3, 7, ...
  511.      -four-up -odd is 3, 11, 19, ... */
  512.  
  513.   if (x2flag)
  514.     if (eflag)
  515.       select_zeros = 0, select_ones = 2;
  516.     else if (oflag)
  517.       select_zeros = 2, select_ones = 0;
  518.     else
  519.       select_zeros = 0, select_ones = 0;
  520.   else if (x4flag)
  521.     if (eflag)
  522.       select_zeros = 0, select_ones = 7;
  523.     else if (oflag)
  524.       select_zeros = 4, select_ones = 3;
  525.     else
  526.        select_zeros = 0, select_ones = 3;
  527.   else
  528.     if (eflag)
  529.       select_zeros = 0, select_ones = 1;
  530.     else if (oflag)
  531.       select_zeros = 1, select_ones = 0;
  532.     else
  533.       select_zeros = 0, select_ones = 0;
  534.  
  535.   /* four-up reads pagenos 1, 3, 5, ... into the bottom half of the
  536.      page buffer.  Everything else reads starting at col 0. */
  537.   if (x4flag)
  538.     select_right_half = 2, select_bottom_half = 1;
  539.   else
  540.     select_right_half = select_bottom_half = 0;
  541.  
  542.   /* two-up and four-up eject with \v instead of \f on alternate pagenos */
  543.   if (x2flag)
  544.     select_top_half = 1;
  545.   else
  546.     select_top_half = 0;
  547.  
  548.   for (pageno = 0; ; pageno++) {
  549.     if (! read_page (pageno & select_bottom_half, pageno & select_right_half))
  550.       break;
  551.     if ((pageno & select_zeros) == 0 && (pageno & select_ones) == select_ones)
  552.       write_page (~ pageno & select_top_half);
  553.   }
  554.  
  555.   /* now PAGENO is the number of the first missing page.  Output a \f
  556.      if there is a half-printed sheet in the printer, or if there is an
  557.      unprinted odd side in the feeder. */
  558.  
  559.   if (x4flag ? (eflag ? (pageno & 7)
  560.         : oflag ? ((pageno & 7) && ! (pageno & 4))
  561.         : (pageno & 3))
  562.       : x2flag ? (eflag ? (pageno & 3)
  563.           : oflag ? ((pageno & 3) && ! (pageno & 2))
  564.           : (pageno & 1))
  565.       : (eflag ? (pageno & 1)
  566.      : 0))
  567.     write_page (0);
  568. }
  569.  
  570. /* Called only for 1-sided.
  571.    Read stdin and build a list of file positions where the pages start. */
  572.  
  573. static void init_reverse ()
  574. {
  575.   int c, lineno;
  576.   unsigned pos;
  577.   struct page_list *page;
  578.  
  579.   for (;;) {
  580.     pos = ftell (stdin);
  581.  
  582.     c = getchar ();
  583.     if (c == EOF)
  584.       goto eof;
  585.  
  586.     npages++;
  587.     page = malloc (sizeof *page);
  588.     page->pos = pos;
  589.     page->next = page_list;
  590.     page_list = page;
  591.  
  592.     lineno = 0;
  593.  
  594.     for ( ; ; c = getchar ()) {
  595.       switch (c) {
  596.       case EOF:
  597.       case '\f':
  598.     goto eop;
  599.  
  600.       when '\n':
  601.     lineno++;
  602.     if (lineno == maxline) {
  603.       c = getchar ();
  604.       if (c != '\f')
  605.         ungetc (c, stdin);
  606.       goto eop; }
  607.     else
  608.       continue;
  609.       }
  610.     }
  611.     eop:;
  612.   }
  613.  eof: ;
  614. }
  615.  
  616. /* Called only for 1-sided.
  617.    Seek stdin to the beginning of the previous page.
  618.    For 1-up, just returns (e.g.) page 5, 4, 3, 2, 1.
  619.    for 2-up, returns 5, <blank>, 3, 4, 1, 2.
  620.    for 4-up, returns, 5, <blank>, <blank>, <blank>, 1, 2, 3, 4.
  621.    returns 1 on success, -1 to insert a blank page, 0 at eof. */
  622.  
  623. static int seek_prev_page ()
  624. {
  625.   static int init, npushed, nextra;
  626.   int n;
  627.  
  628.   if (! init) {
  629.     init = 1;
  630.  
  631.     if (x2flag)
  632.       nextra = npages & 1;
  633.     else if (x4flag)
  634.       if (npages & 3) nextra = 4 - (npages & 3);
  635.  
  636.     for (n = 0; n < nextra; n++) {
  637.       struct page_list *page = malloc (sizeof *page);
  638.       page->pos = page_list->pos;
  639.       page->next = page_list;
  640.       page_list = page; }}
  641.  
  642.   else {
  643.     if (npushed > nextra) {
  644.       npushed--;
  645.       return 1; }
  646.  
  647.     if (nextra) {
  648.       nextra--;
  649.       npushed--;
  650.       return -1; }}
  651.   
  652.   if (! page_list)
  653.     return 0;
  654.  
  655.   if (x2flag) {
  656.     npushed = 1;
  657.     page_list = page_list->next; }
  658.   else if (x4flag) {
  659.     npushed = 3;
  660.     page_list = page_list->next;
  661.     page_list = page_list->next;
  662.     page_list = page_list->next; }
  663.  
  664.   fseek (stdin, page_list->pos, SEEK_SET);
  665.   page_list = page_list->next;
  666.  
  667.   return 1;
  668. }
  669.  
  670. /* Here at the start of a new side, clear the page buffer. */
  671.  
  672. static void init_page ()
  673. {
  674.   memset (buf, ' ', sizeof buf);
  675.   memset (attr, 0, sizeof attr);
  676.  
  677.   while (overstrikes) {
  678.     struct overstrike *next = overstrikes->next;
  679.     free (overstrikes);
  680.     overstrikes = next; }
  681. }
  682.  
  683. /* Read one page into the buffer */
  684.  
  685. static int read_page (int bottom_half_flag, int right_half_flag)
  686. {
  687.   int c, t;
  688.   int lineno, colno;
  689.   uchar *line;
  690.  
  691.   if (! (right_half_flag || bottom_half_flag))
  692.     init_page ();
  693.  
  694.   colno = 0;
  695.   lineno = 0;
  696.   if (bottom_half_flag)
  697.     if (right_half_flag)
  698.       line = &buf[centerline][centercol];
  699.     else
  700.       line = &buf[centerline][0];
  701.   else
  702.     if (right_half_flag)
  703.       line = &buf[0][centercol];
  704.     else
  705.       line = &buf[0][0];
  706.  
  707.   if (reverse) {
  708.     c = seek_prev_page ();
  709.     if (c == 0) 
  710.       return 0;
  711.     if (c == -1)
  712.       return 1;
  713.   }
  714.  
  715.   c = getchar ();
  716.   if (c == EOF)
  717.     return 0;
  718.  
  719.   for ( ; ; c = getchar ()) {
  720.     switch (c) {
  721.     case EOF:
  722.     case '\f':
  723.       return 1;
  724.  
  725.     when '\b':
  726.       if (colno > 0)
  727.     colno--;
  728.       continue;
  729.  
  730.     when '\t':
  731.       colno = (colno + 8) & -8;
  732.       continue;
  733.  
  734.     when ' ':
  735.       colno++;
  736.       continue;
  737.  
  738.     when '\r':
  739.       colno = 0;
  740.       continue;
  741.  
  742.     when '\n':
  743.       colno = 0;
  744.       lineno++, line += MAXCOL;
  745.       if (lineno == maxline) {
  746.     c = getchar ();
  747.     if (c != '\f')
  748.       ungetc (c, stdin);
  749.     return 1; }
  750.       else
  751.     continue;
  752.     }
  753.  
  754.     if (colno > maxcol)
  755.       continue;
  756.  
  757.     if (line[colno] == ' ')
  758.       line[colno] = c;
  759.     else if (line[colno] == c)
  760.       attr[lineno][colno] |= BOLD;
  761.     else if ((t = replace_overstrike (c, line[colno])) != 0)
  762.       line[colno] = t;
  763.     else if (c == '_')
  764.       attr[lineno][colno] |= UNDERLINE;
  765.     else if (line[colno] == '_')
  766.       line[colno] = c, attr[lineno][colno] |= UNDERLINE;
  767.     else {
  768.       struct overstrike *new = malloc (sizeof *new);
  769.       new->charloc = &line[colno];
  770.       new->c = c;
  771.       new->next = overstrikes;
  772.       overstrikes = new;
  773.       attr[lineno][colno] |= OVERSTRIKE; }
  774.     
  775.     colno++;
  776.   }
  777. }
  778.  
  779. /* Write the buffer */
  780.  
  781. static void write_page (int vt_flag)
  782. {
  783.   int lineno, colno;
  784.   int n;
  785.  
  786.   in_page = 1;
  787.  
  788.   for (n = 0; n < top_margin; n++)
  789.     putchar ('\n');
  790.  
  791.   /* for normal output with resident fonts, output the lines one by
  792.      one, going across rows (portrait orientation). */
  793.   if (! myfont)
  794.     for (lineno = topline; lineno < botline; lineno++) {
  795.       write_line (buf[lineno], attr[lineno], 1, maxcol);
  796.       if (lineno != botline - 1)
  797.     putchar ('\n'); }
  798.  
  799.   /* for landscape output with downloaded font, output two lines at
  800.      once, going down columns. */
  801.   else if (lflag || x2flag)
  802.     for (colno = 0; colno < maxcol; colno += 2) {
  803.       write_two_lines (&buf[botline-1][colno], &buf[botline-1][colno+1],
  804.                -MAXCOL, botline - topline);
  805.       if (colno != maxcol - 1)
  806.     putchar ('\n'), putchar ('\n'); }
  807.  
  808.   /* for portrait output with downloaded font, output two lines at
  809.      once, going across rows. */
  810.   else
  811.     for (lineno = topline; lineno < botline; lineno += 2) {
  812.       write_two_lines (buf[lineno], buf[lineno+1], 1, centercol + maxcol);
  813.       if (lineno != botline - 1)
  814.     putchar ('\n'), putchar ('\n'); }
  815.     
  816.   if (vt_flag)
  817.     ;
  818.   else {
  819.     fflush (stdout);        /* wait here for sigint */
  820.     write (STDOUT_FILENO, "\f", 1);
  821.     in_page = 0;
  822.   }
  823. }
  824.  
  825. /* Write one line */
  826.  
  827. static void write_line (uchar *charp, uchar *attrp, int stride, int len)
  828. {
  829.   int c, a, lpa;
  830.   uchar *lastc;
  831.  
  832.   /* skip to left margin */
  833.   do_hskip (left_margin);
  834.  
  835.   /* skip trailing spaces */
  836.   for (lastc = charp + stride * len; lastc != charp; lastc -= stride)
  837.     if (lastc[-stride] != ' ')
  838.       break;
  839.  
  840.   lpa = 0;
  841.  
  842.   for ( ; charp != lastc; charp += stride, attrp += stride) {
  843.     c = *charp;
  844.     a = *attrp;
  845.  
  846.     if (a != lpa) {
  847.       /* use an underlined space for _ if both chars
  848.      next to it are underlined. */
  849.       if (c == '_'
  850.       && ! (a & UNDERLINE)
  851.       && (lpa & UNDERLINE)
  852.       && (attrp[stride] & UNDERLINE))
  853.     c = ' ', a |= UNDERLINE;
  854.       /* use an underlined _ for bold _ if both chars
  855.      next to it are underlined and not bold. */
  856.       if (c == '_'
  857.       && (a & BOLD)
  858.       && (lpa & UNDERLINE) && ! (lpa & BOLD)
  859.       && (attrp[stride] & UNDERLINE) && ! (attrp[stride] & BOLD))
  860.     a = UNDERLINE;
  861.       /* send attr escape sequence */
  862.       lpa = setattr (lpa, a);
  863.       /* send generic overstrikes */
  864.       if (a & OVERSTRIKE) {
  865.     do_overstrikes (charp);
  866.     a &= ~OVERSTRIKE; }
  867.     }
  868.  
  869.     /* quote chars in 000..037 and 0177..237 */
  870.     if ((c & 0140) == 0 || c == 0177)
  871.       send_quoted (c);
  872.     else
  873.       putchar (c);
  874.   }
  875.   
  876.   /* turn attrs off at end of line */
  877.   if (lpa != 0)
  878.     lpa = setattr (lpa, 0);
  879. }
  880.  
  881. /* Send escape sequence to change bold/underline attrs from LPA to A */
  882.  
  883. static int setattr (int lpa, int a)
  884. {
  885.   if (! myfont) {
  886.     if ((a & BOLD) && ! (lpa & BOLD))
  887.       bold_on ();
  888.     if (! (a & BOLD) && (lpa & BOLD))
  889.       bold_off ();
  890.     if ((a & UNDERLINE) && ! (lpa & UNDERLINE))
  891.       underline_on ();
  892.     if (! (a & UNDERLINE) && (lpa & UNDERLINE))
  893.       underline_off (); }
  894.  
  895.   return a & (BOLD | UNDERLINE);
  896. }
  897.  
  898. /* Send generic overstrikes */
  899.  
  900. static void do_overstrikes (uchar *charloc)
  901. {
  902.   struct overstrike *p;
  903.  
  904.   for (p = overstrikes; p; p = p->next)
  905.     if (p->charloc == charloc)
  906.       putchar (p->c), putchar ('\b');
  907. }
  908.  
  909. /* Send two lines (or cols) to the printer */
  910.  
  911. static void write_two_lines (uchar *c1, uchar *c2, int stride, int len)
  912. {
  913.   uchar *last1, *last2;
  914.  
  915.   /* skip trailing spaces */
  916.   last1 = c1 + stride * len;
  917.   last2 = c2 + stride * len;
  918.   for ( ; last1 != c1; last1 -= stride, last2 -= stride)
  919.     if (last1[-stride] != ' ' || last2[-stride] != ' ')
  920.       break;
  921.  
  922.   /* send the lines, one above the other */
  923.   for ( ; c1 != last1; c1 += stride, c2 += stride)
  924.     send_pair (*c1, *c2);
  925.  
  926.   /* flush send_pair's buffer */
  927.   send_linebuf (left_margin);
  928. }
  929.  
  930. /* Here on `^C' from lpd -- abort job.  Don't leave a half-printed page
  931.    in the printer.  Does not output data waiting in stdio buffers.
  932.    There's no way to cancel data buffered in the kernel. */
  933.  
  934. void sigint (int signo)
  935. {
  936.   const char *fin;
  937.   int len;
  938.  
  939.   if (in_page) {
  940.     static const char nulls[240];
  941.       
  942.     /* send a bunch of nulls to complete any partial escape sequence */
  943.     write (STDOUT_FILENO, nulls, sizeof nulls);
  944.  
  945.     /* send ^X to flush the printer's buffer, and \f to
  946.        eject the partial page */
  947.     write (STDOUT_FILENO, "\030\f", 2);
  948.   }
  949.  
  950.   /* reset printer state to something sensible */
  951.   fin_string (&fin, &len);
  952.   write (STDOUT_FILENO, fin, len);
  953.  
  954.   /* obey sigint */
  955.   _exit (0);
  956. }
  957.